package com.spring.security.core.aop;
import java.lang.reflect.Method;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.spring.security.core.annotation.Log;
import com.spring.security.core.annotation.LogModel;
import com.spring.security.core.util.ApplicationUtils;
import com.spring.security.core.util.UDate;

@Aspect
@Component
public class SpringLog {
	ThreadLocal<Long> time=new ThreadLocal<Long>();
	ThreadLocal<String> tag=new ThreadLocal<String>();
	@Resource
	private MongoTemplate mongoService;
	
	@Pointcut("@annotation(com.spring.security.core.annotation.Log)")
	public void log(){
//		System.out.println("----->aop in");
	}
	
	/**
	 * 在所有标注@Log的地方切入
	 * @param joinPoint
	 */
	@Before("log()")
	public void beforeExec(JoinPoint joinPoint){
		
		time.set(System.currentTimeMillis());
		tag.set(ApplicationUtils.randomUUID().toString());
//		info(joinPoint);
//		MethodSignature ms=(MethodSignature) joinPoint.getSignature();
//		Method method=ms.getMethod();
//		System.out.println(method.getAnnotation(Log.class).value()+"------>"+tag.get());
	}
	
	@After("log()")
	public void afterExec(JoinPoint joinPoint){
//		MethodSignature ms=(MethodSignature) joinPoint.getSignature();
//		Method method=ms.getMethod();
//		System.out.println("----->"+tag.get()+"--->function:"+method.getName()+";usetime:"+(System.currentTimeMillis()-time.get())+"ms");
		info(joinPoint,"success","execute success");
	}
	
	@AfterThrowing(pointcut = "log()", throwing = "e")    
	public void afterExecThrowing(JoinPoint joinPoint, Throwable e){
//		MethodSignature ms=(MethodSignature) joinPoint.getSignature();
//		Method method=ms.getMethod();
//		System.out.println("----->"+tag.get()+"--->function:"+method.getName()+";usetime:"+(System.currentTimeMillis()-time.get())+"ms");
//		String ret = e.getMessage();
//		System.out.println("=====异常通知开始=====");    
//        System.out.println("异常代码:" + e.getClass().getName());    
//        System.out.println("异常信息:" + e.getMessage());    
//        System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));    
		info(joinPoint,"failer",e.getClass().getName());
	}
	
//	@Around("log()")
//	public Object aroundExec(ProceedingJoinPoint pjp) throws Throwable{
//		Object result = null;//result的值就是被拦截方法的返回值  
//		String ret = "execute success";
//		try{
//			result = pjp.proceed();
//			info(pjp,"success",ret);
//		}catch(Exception e){
////			ret = e.getMessage().length()>1000?e.getMessage().substring(0,1000):e.getMessage();
//			info(pjp,"failer","execute failer");
////			throw e;
//		}
//	    return result;  
//	}
	
	private void info(JoinPoint joinPoint,String success,String result){
//		System.out.println("--------------------------------------------------");
//		System.out.println("King:\t"+joinPoint.getKind());
		MethodSignature ms=(MethodSignature) joinPoint.getSignature();
		Method method=ms.getMethod();
		/**
		 * 方法名
		 */
		String funName = method.getName();
		/**
		 * 方法执行时长
		 */
		String useTime = (System.currentTimeMillis()-time.get())+"";
//		System.out.println("----->"+tag.get()+"--->function:"+method.getName()+";usetime:"+(System.currentTimeMillis()-time.get())+"ms");
		
		RequestAttributes ra = RequestContextHolder.getRequestAttributes();  
	    ServletRequestAttributes sra = (ServletRequestAttributes)ra;  
	    HttpServletRequest request = sra.getRequest();  
	    /**
	     * 服务器IP
	     */
	    String toIp = request.getLocalAddr();  
	    /**
	     * 访问服务器URL
	     */
	    String toUrl = request.getRequestURL()+"";
	    /**
	     * 访问者IP
	     */
	    String fromIp = getIpAddr(request);
	    
		
//		System.out.println("Target:\t"+joinPoint.getTarget().toString());
		Object[] os=joinPoint.getArgs();
		/**
		 * 方法参数
		 */
		StringBuffer sb = new StringBuffer();
//		System.out.println("Args:");
		for(int i=0;i<os.length;i++){
			if(ApplicationUtils.isNotNull(os[i])){
				sb.append("parm["+i+"]:"+ApplicationUtils.Object2String(os[i])+";");
//				System.out.println("\t==>parm["+i+"]:\t"+ApplicationUtils.Object2String(os[i]));
			}
		}
		LogModel lm = new LogModel();
		lm.setFunName(funName).setFunParm(sb.toString()).setUseTime(useTime).setRequestFromIp(fromIp).setResult(result)
			.setRequestToUrl(toUrl).setRequestToIp(toIp).setFunNote(method.getAnnotation(Log.class).value()).setIsSuccess(success)
			.setRequestEndTime(UDate.getDate("yyyy-MM-dd HH:mm:ss"));
		mongoService.insert(lm);
//		System.out.println(sb.toString());
//		System.out.println("Signature:\t"+joinPoint.getSignature());
//		System.out.println("SourceLocation:\t"+joinPoint.getSourceLocation());
//		System.out.println("StaticPart:\t"+joinPoint.getStaticPart());
//		System.out.println("--------------------------------------------------");
	}
	
	/**
	 * 获取访问者IP
	 * @param request
	 * @return
	 */
	public String getIpAddr(HttpServletRequest request) {
		 String ip = request.getHeader("x-forwarded-for");
		 if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
		  ip = request.getHeader("Proxy-Client-IP");
		 }
		 if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
		  ip = request.getHeader("WL-Proxy-Client-IP");
		 }
		 if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
		  ip = request.getRemoteAddr();
		 }
		 if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
		  ip = request.getHeader("http_client_ip");
		 }
		 if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
		  ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		 }
		 // 如果是多级代理，那么取第一个ip为客户ip
		 if (ip != null && ip.indexOf(",") != -1) {
		  ip = ip.substring(ip.lastIndexOf(",") + 1, ip.length()).trim();
		 }
		 return ip;
	}
	
	
	
//	@Around("log()")
//	public void aroundExec(ProceedingJoinPoint pjp) throws Throwable{
//		MethodSignature ms=(MethodSignature) pjp.getSignature();
//		Method method=ms.getMethod();
//		System.out.println("-------->"+method.getName());
//	}
}
